home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / ARP.C < prev    next >
C/C++ Source or Header  |  1997-09-07  |  13KB  |  434 lines

  1. /* Address Resolution Protocol (ARP) functions. Sits between IP and
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  * Level 2, mapping IP to Level 2 addresses for all outgoing datagrams.
  4.  *
  5.  * Mods by G1EMM
  6.  *
  7.  * Mods by SM6RPZ
  8.  * 1992-05-28 - Added interface to arp_lookup() and arp_add().
  9.  * 1992-07-07 - Added arp_timeout(). This function now works according to the
  10.  *              last page in RFC826. When an ARP entry times out we will first
  11.  *              try an ARP reply before deleting the entry.
  12.  * 1992-07-08 - We will update the ARP table and create new entries each time
  13.  *              we hear an ARP request message on the channel. By doing so we
  14.  *              will gain knowledge of other stations hardware addresses
  15.  *              whithout sending a lot of ARP requests. If we are running RSPF,
  16.  *              it will be informed about these "findings".
  17.  * 1992-07-11 - Datagrams to be sent while awaiting an resolution will be put
  18.  *              on a queue. The length of this queue in datagrams is defined
  19.  *              in arp.h (ARP_QUEUE).
  20.  *
  21.  * 1992-10-27 The above 3 behaviours are now configurable via additional
  22.  *      arp subcommands - WG7J
  23.  *
  24.  */
  25.  
  26. #include "global.h"
  27. #include "mbuf.h"
  28. #include "timer.h"
  29. #include "iface.h"
  30. #ifdef ETHER
  31. #include "enet.h"
  32. #endif
  33. #include "icmp.h"
  34. #include "arp.h"
  35. #include "rspf.h"
  36. #include "pktdrvr.h"
  37.  
  38. #if !defined(_lint)
  39. static char rcsid[] OPTIONAL = "$Id: arp.c,v 1.16 1997/09/07 21:18:28 root Exp root $";
  40. #endif
  41.  
  42. extern int Maxarpq;
  43. extern int ArpExpire;
  44.  
  45. static void arp_output (struct iface * iface, int16 hardware, uint32 target, char *hw_addr);
  46. static void arp_timeout (void *p);    /* sm6rpz */
  47.  
  48. extern char ArpDupcall[AXALEN];
  49.  
  50. /* Hash table headers */
  51. struct arp_tab *Arp_tab[HASHMOD];
  52. struct arp_stat Arp_stat = {0, 0, 0, 0, 0, 0, 0};
  53.  
  54.  
  55. /* Resolve an IP address to a hardware address; if not found,
  56.  * initiate query and return NULLCHAR.  If an address is returned, the
  57.  * interface driver may send the packet; if NULLCHAR is returned,
  58.  * res_arp() will have saved the packet on its pending queue,
  59.  * so no further action (like freeing the packet) is necessary.
  60.  */
  61. char *
  62. res_arp (iface, hardware, target, bp)
  63. struct iface *iface;        /* Pointer to interface block */
  64. int16 hardware;            /* Hardware type */
  65. uint32 target;            /* Target IP address */
  66. struct mbuf *bp;        /* IP datagram to be queued if unresolved */
  67. {
  68. register struct arp_tab *arp;
  69. struct ip ip;
  70.  
  71.     if ((arp = arp_lookup (hardware, target, iface)) != NULLARP && arp->state == ARP_VALID)
  72.         return arp->hw_addr;
  73.     if (arp != NULLARP) {
  74.         if (len_q (arp->pending) > Maxarpq) {
  75.             /* Earlier packets are already pending, kick
  76.              * this one back as a source quench
  77.              */
  78.             (void) ntohip (&ip, &bp);
  79.             (void) icmp_output (&ip, bp, ICMP_QUENCH, 0, NULL);
  80.             free_p (bp);
  81.         } else
  82.             enqueue (&arp->pending, bp);
  83.     } else {
  84.         /* Create an entry and put the datagram on the
  85.          * queue pending an answer
  86.          */
  87.         arp = arp_add (target, hardware, NULLCHAR, 0, iface);
  88.         enqueue (&arp->pending, bp);
  89.         arp_output (iface, hardware, target, NULLCHAR);
  90.     }
  91.     return NULLCHAR;
  92. }
  93.  
  94.  
  95. /* Handle incoming ARP packets. This is almost a direct implementation of
  96.  * the algorithm on page 5 of RFC 826, except for:
  97.  * 1. Outgoing datagrams to unresolved addresses are kept on a queue
  98.  *    pending a reply to our ARP request.
  99.  * 2. The names of the fields in the ARP packet were made more mnemonic.
  100.  * 3. Requests for IP addresses listed in our table as "published" are
  101.  *    responded to, even if the address is not our own.
  102.  */
  103. void
  104. arp_input (iface, bp)
  105. struct iface *iface;
  106. struct mbuf *bp;
  107. {
  108. struct arp arp;
  109. struct arp_tab *ap;
  110. struct arp_type *at;
  111. int i;
  112.  
  113.     Arp_stat.recv++;
  114.     if (ntoharp (&arp, &bp) == -1)    /* Convert into host format */
  115.         return;
  116.     if (arp.hardware >= NHWTYPES) {
  117.         /* Unknown hardware type, ignore */
  118.         Arp_stat.badtype++;
  119.         return;
  120.     }
  121.     at = &Arp_type[arp.hardware];
  122.     if (arp.protocol != at->iptype) {
  123.         /* Unsupported protocol type, ignore */
  124.         Arp_stat.badtype++;
  125.         return;
  126.     }
  127.     if ((int16) uchar (arp.hwalen) > MAXHWALEN || uchar (arp.pralen) != sizeof (int32)) {
  128.         /* Incorrect protocol addr length (different hw addr lengths
  129.          * are OK since AX.25 addresses can be of variable length)
  130.          */
  131.         Arp_stat.badlen++;
  132.         return;
  133.  
  134.     }
  135.     if (arp.sprotaddr == 0L || arp.tprotaddr == 0L) {
  136.         /* We are going to dead-end references for [0.0.0.0], since
  137.          * experience shows that these cause total lock up -- N1BEE
  138.          */
  139.         Arp_stat.badaddr++;
  140.         return;
  141.     }
  142.     if (memcmp (arp.shwaddr, at->bdcst, (size_t) at->hwalen) == 0) {
  143.         /* This guy is trying to say he's got the broadcast address! */
  144.         Arp_stat.badaddr++;
  145.         return;
  146.     }
  147.     /* Try to refine ARP according to section 5.7 in Douglas E.
  148.      * Comers book "Internetworking With TCP/IP", 2nd ed. page 77.
  149.      * I.e we will use all ARP-packets we can see thereby lessen
  150.      * the ARP traffic a little. -- sm6rpz
  151.      */
  152.     if (((ap = arp_lookup (arp.hardware, arp.sprotaddr, iface)) != NULLARP
  153.          && dur_timer (&ap->timer) != 0)
  154.         || ((iface->flags & ARP_EAVESDROP) &&
  155.         ap == NULLARP && arp.opcode != REVARP_REQUEST)
  156.         ) {
  157.         ap = arp_add (arp.sprotaddr, arp.hardware, arp.shwaddr, 0, iface);
  158.     }
  159.     /* See if we're the address they're looking for */
  160.     if (ismyaddr (arp.tprotaddr) != NULLIF) {
  161.         if (ap == NULLARP)    /* Only if not already in the table */
  162.             (void) arp_add (arp.sprotaddr, arp.hardware, arp.shwaddr, 0, iface);
  163.  
  164.         if (arp.opcode == ARP_REQUEST) {
  165.             /* Swap sender's and target's (us) hardware and protocol
  166.              * fields, and send the packet back as a reply
  167.              */
  168.             memcpy (arp.thwaddr, arp.shwaddr, (size_t) uchar (arp.hwalen));
  169.             /* Mark the end of the sender's AX.25 address
  170.              * in case he didn't
  171.              */
  172.             if (arp.hardware == ARP_AX25)
  173.                 arp.thwaddr[uchar (arp.hwalen) - 1] |= E;
  174.  
  175.             if (iface->type == CL_AX25)
  176.                 memcpy (arp.shwaddr, iface->ipcall, (size_t) at->hwalen);
  177.             else
  178.                 memcpy (arp.shwaddr, iface->hwaddr, (size_t) at->hwalen);
  179.  
  180.             arp.tprotaddr = arp.sprotaddr;
  181.             arp.sprotaddr = iface->addr;
  182.             if (ismyaddr (arp.sprotaddr) == NULLIF)
  183.                 return;
  184.             arp.opcode = ARP_REPLY;
  185.             if ((bp = htonarp (&arp)) == NULLBUF)
  186.                 return;
  187.  
  188.             if (iface->forw != NULLIF)
  189.                 (void) (*iface->forw->output) (iface->forw,
  190.                             arp.thwaddr, iface->forw->ipcall, at->arptype, bp);
  191.             else
  192.                 (void) (*iface->output) (iface, arp.thwaddr,
  193.                         iface->ipcall, at->arptype, bp);
  194.             Arp_stat.inreq++;
  195. #ifdef  RSPF
  196.             /* Do an RSPF upcall */
  197.             rspfarpupcall (arp.tprotaddr, arp.hardware, NULLIF);
  198. #endif /* RSPF*/
  199.         } else {
  200.             Arp_stat.replies++;
  201. #ifdef  RSPF
  202.             /* Do an RSPF upcall */
  203.             rspfarpupcall (arp.sprotaddr, arp.hardware, iface);
  204. #endif /* RSPF*/
  205.         }
  206.     } else if (arp.opcode == ARP_REQUEST
  207.            && (ap = arp_lookup (arp.hardware, arp.tprotaddr, iface)) != NULLARP
  208.            && ap->pub) {
  209.         /* Otherwise, respond if the guy he's looking for is
  210.          * published in our table.
  211.          */
  212.         memcpy (arp.thwaddr, arp.shwaddr, (size_t) uchar (arp.hwalen));
  213.         memcpy (arp.shwaddr, ap->hw_addr, (size_t) at->hwalen);
  214.         arp.tprotaddr = arp.sprotaddr;
  215.         arp.sprotaddr = ap->ip_addr;
  216.         arp.opcode = ARP_REPLY;
  217.         if ((bp = htonarp (&arp)) == NULLBUF)
  218.             return;
  219.         if (iface->forw != NULLIF)
  220.             (void) (*iface->forw->output) (iface->forw,
  221.                 arp.thwaddr, iface->forw->ipcall, at->arptype, bp);
  222.         else
  223.             (void) (*iface->output) (iface, arp.thwaddr,
  224.                   iface->ipcall, at->arptype, bp);
  225.         Arp_stat.inreq++;
  226.     } else if (arp.opcode == REVARP_REQUEST) {
  227.         for (i = 0; i < HASHMOD; i++)
  228.             for (ap = Arp_tab[i]; ap != NULLARP; ap = ap->next)
  229.                 if (memcmp (ap->hw_addr, arp.thwaddr, (size_t) at->hwalen) == 0)
  230.                     goto found;
  231. found:
  232.         if (ap != NULLARP && ap->pub) {
  233.             memcpy (arp.shwaddr, iface->hwaddr, (size_t) at->hwalen);
  234.             arp.tprotaddr = ap->ip_addr;
  235.             arp.sprotaddr = iface->addr;
  236.             arp.opcode = REVARP_REPLY;
  237.             if ((bp = htonarp (&arp)) == NULLBUF)
  238.                 return;
  239.             if (iface->forw != NULLIF)
  240.                 (void) (*iface->forw->output) (iface->forw,
  241.                     arp.thwaddr, iface->forw->ipcall, REVARP_TYPE, bp);
  242.             else
  243.                 (void) (*iface->output) (iface, arp.thwaddr,
  244.                     iface->ipcall, REVARP_TYPE, bp);
  245.             Arp_stat.inreq++;
  246.         }
  247.     }
  248. }
  249.  
  250.  
  251. /* Add an IP-addr / hardware-addr pair to the ARP table */
  252. struct arp_tab *
  253. arp_add (ipaddr, hardware, hw_addr, pub, iface)
  254. uint32 ipaddr;            /* IP address, host order */
  255. int16 hardware;            /* Hardware type */
  256. char *hw_addr;            /* Hardware address, if known; NULLCHAR otherwise */
  257. int pub;            /* Publish this entry? */
  258. struct iface *iface;
  259. {
  260. struct mbuf *bp;
  261. register struct arp_tab *ap;
  262. struct arp_type *at;
  263. unsigned hashval;
  264.  
  265.     if (hardware >= NHWTYPES)
  266.         return NULLARP;    /* Invalid hardware type */
  267.     at = &Arp_type[hardware];
  268.  
  269.     if ((ap = arp_lookup (hardware, ipaddr, iface)) == NULLARP) {
  270.         /* New entry */
  271.         ap = (struct arp_tab *) callocw (1, sizeof (struct arp_tab));
  272.  
  273.         ap->hw_addr = mallocw ((unsigned) at->hwalen);
  274.         ap->timer.func = arp_timeout;
  275.         ap->timer.arg = ap;
  276.         ap->hardware = hardware;
  277.         ap->ip_addr = ipaddr;
  278.         ap->iface = iface;
  279.  
  280.         /* Put on head of hash chain */
  281.         hashval = hash_ip (ipaddr);
  282.         ap->prev = NULLARP;
  283.         ap->next = Arp_tab[hashval];
  284.         Arp_tab[hashval] = ap;
  285.         if (ap->next != NULLARP) {
  286.             ap->next->prev = ap;
  287.         }
  288.     }
  289.     if (hw_addr == NULLCHAR) {
  290.         /* Await response */
  291.         ap->state = ARP_PENDING;
  292.         set_timer (&ap->timer, Arp_type[hardware].pendtime * 1000L);
  293.     } else {
  294.         /* Response has come in, update entry and run through queue */
  295.         ap->state = ARP_VALID;
  296.         set_timer (&ap->timer, ArpExpire * 1000L);
  297.         memcpy (ap->hw_addr, hw_addr, (size_t) at->hwalen);
  298.         ap->pub = (char) pub;
  299.         while ((bp = dequeue (&ap->pending)) != NULLBUF)
  300.             (void) ip_route (NULLIF, bp, 0);
  301.     }
  302.     start_detached_timer (&ap->timer);
  303.     return ap;
  304. }
  305.  
  306.  
  307. /* Remove an entry from the ARP table */
  308. void
  309. arp_drop (p)
  310. void *p;
  311. {
  312. register struct arp_tab *ap;
  313.  
  314.     ap = (struct arp_tab *) p;
  315.     if (ap == NULLARP)
  316.         return;
  317.     stop_timer (&ap->timer);/* Shouldn't be necessary */
  318.     if (ap->next != NULLARP)
  319.         ap->next->prev = ap->prev;
  320.     if (ap->prev != NULLARP)
  321.         ap->prev->next = ap->next;
  322.     else
  323.         Arp_tab[hash_ip (ap->ip_addr)] = ap->next;
  324.     free_q (&ap->pending);
  325.     free (ap->hw_addr);
  326.     free ((char *) ap);
  327. }
  328.  
  329.  
  330. /* Look up the given IP address in the ARP table */
  331. struct arp_tab *
  332. arp_lookup (hardware, ipaddr, iface)
  333. int16 hardware;
  334. uint32 ipaddr;
  335. struct iface *iface;
  336. {
  337. register struct arp_tab *ap;
  338.  
  339.     for (ap = Arp_tab[hash_ip (ipaddr)]; ap != NULLARP; ap = ap->next) {
  340.         if (ap->ip_addr == ipaddr && ap->hardware == hardware \
  341.             &&ap->iface == iface)
  342.             break;
  343.     }
  344.     return ap;
  345. }
  346.  
  347.  
  348. /* Send an ARP request to resolve IP address target_ip */
  349. static void
  350. arp_output (iface, hardware, target, hw_addr)
  351. struct iface *iface;
  352. int16 hardware;
  353. uint32 target;
  354. char *hw_addr;
  355. {
  356. struct arp arp;
  357. struct mbuf *bp;
  358. struct arp_type *at;
  359.  
  360.     at = &Arp_type[hardware];
  361.     if (iface->output == NULLFP ((struct iface *, const char *, char *, int16, struct mbuf *)))
  362.         return;
  363.  
  364.     arp.hardware = hardware;
  365.     arp.protocol = at->iptype;
  366.     arp.hwalen = (char) at->hwalen;
  367.     arp.pralen = sizeof (int32);
  368.     arp.opcode = ARP_REQUEST;
  369.  
  370.     if (iface->type == CL_AX25)
  371.         memcpy (arp.shwaddr, iface->ipcall, (size_t) at->hwalen);
  372.     else
  373.         memcpy (arp.shwaddr, iface->hwaddr, (size_t) at->hwalen);
  374.  
  375.     arp.sprotaddr = iface->addr;
  376.     memset (arp.thwaddr, 0, (size_t) at->hwalen);
  377.     arp.tprotaddr = target;
  378.     if ((bp = htonarp (&arp)) == NULLBUF)
  379.         return;
  380.     if ((iface->type == CL_AX25) && *ArpDupcall) {
  381.         struct mbuf *bpc;
  382.  
  383.         bpc = copy_p (bp, ARPLEN + 2 * uchar (arp.hwalen));
  384.         (void) (*iface->output) (iface, ArpDupcall, iface->ipcall, at->arptype, bp);
  385.         bp = bpc;
  386.     }
  387.     if (hw_addr == NULLCHAR) {
  388.         if (iface->type == CL_AX25)
  389.             (void) (*iface->output) (iface, at->bdcst, iface->ipcall, at->arptype, bp);
  390.         else
  391.             (void) (*iface->output) (iface, at->bdcst, iface->hwaddr, at->arptype, bp);
  392.     } else if (iface->type == CL_AX25)
  393.         (void) (*iface->output) (iface, hw_addr, iface->ipcall, at->arptype, bp);
  394.     else
  395.         (void) (*iface->output) (iface, hw_addr, iface->hwaddr, at->arptype, bp);
  396.     Arp_stat.outreq++;
  397. }
  398.  
  399.  
  400. /* Called when an ARP entry times out. If an entry has been a valid
  401.  * one we will send out an ARP reply. If this one does not succed,
  402.  * the ARP entry will be dropped. -- sm6rpz
  403.  *
  404.  * Made configurable by WG7J.
  405.  */
  406. static void
  407. arp_timeout (p)
  408. void *p;
  409. {
  410. struct arp_type *at;
  411. char *hwaddr;
  412. struct arp_tab *ap = (struct arp_tab *) p;
  413.  
  414.     if (ap == NULLARP)
  415.         return;
  416.     stop_timer (&ap->timer);
  417.     /* Check to see if the timer is set to ARPLIFE/ArpExpire or pendtime. Set_timer()
  418.      * adds at least one tick so we must do a little more flexible check.
  419.      */
  420.     if ((ap->iface->flags & ARP_KEEPALIVE) &&
  421.         (dur_timer (&ap->timer) >= /* ARPLIFE */ ArpExpire * 1000L)) {
  422.         at = &Arp_type[ap->hardware];
  423.         set_timer (&ap->timer, at->pendtime * 1000L);
  424.         /* timer functions should NEVER call blocked allocs ! - WG7J */
  425.         if ((hwaddr = (char *) mallocw ((unsigned) at->hwalen)) != NULLCHAR) {
  426.             memcpy (hwaddr, ap->hw_addr, (size_t) at->hwalen);
  427.             arp_output (ap->iface, ap->hardware, ap->ip_addr, hwaddr);
  428.             free (hwaddr);    /* clean up */
  429.         }
  430.         start_detached_timer (&ap->timer);
  431.     } else
  432.         arp_drop (ap);
  433. }
  434.